package logic

import (
	"album/domain"
	"album/internal/svc"
	"album/kafka/client"
	"context"
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/google/uuid"
	"github.com/jinzhu/copier"
	"github.com/mozillazg/go-pinyin"
	"github.com/zeromicro/go-zero/core/logx"
	"gorm.io/gorm"
	"grpc-common/album/types/album"
	"grpc-common/search/types/search"
	"grpc-common/ucenter/types/login"
	"grpc-common/ucenter/ucclient"
	"listenboos-common/bloom"
	"listenboos-common/db"
	"listenboos-common/db/tran"
	"listenboos-common/kafka/model"
	"listenboos-common/redis"
	model_redis "listenboos-common/redis/model"
	"listenboos-common/tools"
	"math/rand"
	"strconv"
	"sync"
	"time"
)

const layout = "20060102"

type AlbumLogic struct {
	ctx             context.Context
	wg              sync.WaitGroup
	svcCtx          *svc.ServiceContext
	albumInfoDomain *domain.AlbumInfoDomain
	attribute       *domain.AttributeDomain
	transaction     tran.Transaction
	albumStatDomain *domain.AlbumStatDomain
	trackInfoDomain *domain.TrackInfoDomain
	trackStatDomain *domain.TrackStatDomain
	processDomain   *domain.ProcessDomain
	redisClient     *redis.RedisClient
	orderInfoDomain *domain.OrderInfoDomain
	//kafkaProducer   *client.KafkaProducer
	logx.Logger
}

func NewAlbumLogicLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AlbumLogic {
	//sss, err := sarama.NewSyncProducerFromClient(svcCtx.KafkaClient)
	//if err != nil {
	//	logx.Errorf("NewAlbumLogicLogic error:%v", err)
	//	return nil
	//}
	return &AlbumLogic{
		ctx:             ctx,
		svcCtx:          svcCtx,
		albumInfoDomain: domain.NewAlbumInfoDomain(svcCtx.DB),
		attribute:       domain.NewAttributeDomain(svcCtx.DB),
		Logger:          logx.WithContext(ctx),
		transaction:     tran.NewTransaction(svcCtx.DB.Conn),
		albumStatDomain: domain.NewAlbumStatDomain(svcCtx.DB),
		trackInfoDomain: domain.NewTrackInfoDomain(svcCtx.DB),
		trackStatDomain: domain.NewTrackStatDomain(svcCtx.DB),
		processDomain:   domain.NewProcessDomain(svcCtx.MongoClient),
		redisClient:     redis.NewRedisClient(),
		orderInfoDomain: domain.NewOrderInfoDomain(svcCtx.DB),
		//kafkaProducer:   client.NewKafkaProducer(client.NewSyncProducer(svcCtx.KafkaClient)),
		//kafkaProducer: client.NewKafkaProducer(client.NewSyncProducer(c)),
	}
}
func (l *AlbumLogic) FindAlbumInfo(in *album.FindAlbumInfoReq) (*album.FindAlbumInfoResp, error) {
	test := bloom.Bloom.Filter.Test([]byte(fmt.Sprintf("%d", in.AlbumId)))
	if !test {
		return nil, errors.New("专辑不存在")
	}
	// 查一下属性
	key := fmt.Sprintf("albumInfo:%d", in.AlbumId)
	res := &album.FindAlbumInfoResp{}
	err := l.svcCtx.Cache.Get(key, &res)
	if res.AlbumInfo != nil && err == nil {
		return res, nil
	}
	//TODO:4个调用可以开协程优化
	// 加分布式锁的原因是防止大量redis没有的数据请求进来，导致进入数据库查询，防止数据库压力过大
	// 一直查一个没有的id怎么办，布隆过滤器
	redisLock := redis.NewRedisClient()
	mutex := redisLock.Mutex(key)
	err = mutex.Lock()
	var req search.FindAlbumInfoReq
	err = copier.Copy(&req, &in)
	if err != nil {
		return nil, err
	}
	//info, err := l.svcCtx.SearchRpc.FindAlbumInfo(l.ctx, &req)
	info, err := l.albumInfoDomain.FindAlbumById(l.ctx, in.AlbumId)
	if err != nil {
		logx.Errorf("rpc 调用SearchAlbumInfo 失败 error: %v", err)
		return nil, err
	}
	albumInfo := album.DetailResp{}
	err = copier.Copy(&albumInfo, &info)
	// 查询属性
	var AlbumAttributeValues []*album.AlbumAttributeValue
	attributeValues, err := l.attribute.FindByAid(l.ctx, in.AlbumId)
	if err != nil {
		return nil, err
	}
	for _, attributeValue := range attributeValues {
		// 查询attribute
		fmt.Println("-------------")
		fmt.Println("进入数据库查询")
		attribute, err := l.attribute.FindAttributeById(l.ctx, attributeValue.AttributeId)
		if err != nil {
			return nil, err
		}
		Values, err := l.attribute.FindAttributeValuesById(l.ctx, attributeValue.ValueId)
		if err != nil {
			return nil, err
		}
		albumAttributeValue := album.AlbumAttributeValue{}
		albumAttributeValue.ValueId = Values.Id
		albumAttributeValue.AlbumId = in.AlbumId
		albumAttributeValue.AttributeId = attribute.Id
		albumAttributeValue.AttributeName = attribute.AttributeName
		albumAttributeValue.ValueName = Values.ValueName
		AlbumAttributeValues = append(AlbumAttributeValues, &albumAttributeValue)
	}
	err = copier.Copy(&albumInfo.AlbumAttributeValueList, AlbumAttributeValues)
	if err != nil {
		return nil, err
	}
	// 查找用户信息
	ureq := ucclient.UserInfoIdReq{}
	ureq.UserId = info.UserId
	userInfo, err := l.svcCtx.UCLoginRpc.GetUserInfoByUserId(l.ctx, &ureq)
	if err != nil {
		//error处理一次之后不应该再往上抛了
		logx.Errorf("rpc 调用SearchAlbumInfo 失败 error: %v", err)
		return nil, nil
	}
	ures := album.Announcer{}
	err = copier.Copy(&ures, &userInfo)
	// 查找三级分类信息
	category3, err := l.albumInfoDomain.FindCategory3ById(l.ctx, info.Category3Id)
	if err != nil {
		//error处理一次之后不应该再往上抛了
		return nil, err
	}
	var cres album.BaseCategoryView
	cres.Id = info.Id
	cres.Category3Id = category3.Id
	cres.Category3Name = category3.Name
	category2, err := l.albumInfoDomain.FindCategory2ById(l.ctx, category3.Category2Id)
	cres.Category2Id = category2.Id
	cres.Category2Name = category2.Name
	category1, err := l.albumInfoDomain.FindCategory1ById(l.ctx, category2.Category1Id)
	cres.Category1Id = category1.Id
	cres.Category1Name = category1.Name
	cres.CreateTime = category3.CreateTime
	// 查询专辑统计信息
	var statres album.AlbumStatVo
	playStatNum, subscribeStatNum, buyStatNum, commentStatNum, err := l.albumStatDomain.FindByAlbumId(l.ctx, in.AlbumId)
	statres.PlayStatNum, _ = strconv.ParseInt(playStatNum, 10, 64)
	statres.AlbumId = in.AlbumId
	statres.BuyStatNum, _ = strconv.ParseInt(buyStatNum, 10, 64)
	statres.SubscribeStatNum, _ = strconv.ParseInt(subscribeStatNum, 10, 64)
	statres.CommentStatNum, _ = strconv.ParseInt(commentStatNum, 10, 64)
	res.AlbumInfo = &albumInfo
	res.Announcer = &ures
	res.BaseCategoryView = &cres
	res.AlbumStatVo = &statres
	//	res.AlbumStatVo.PlayStatNum = 100
	err = l.svcCtx.Cache.Set(key, &res)
	if err != nil {
		return nil, err
	}
	if ok, err := mutex.Unlock(); !ok || err != nil {
		logx.Errorf("GetAlbumInfoById unloak faild error:%v", err)
		return nil, errors.New("释放分布式锁错误")
	}
	return &album.FindAlbumInfoResp{AlbumInfo: &albumInfo, Announcer: &ures, BaseCategoryView: &cres, AlbumStatVo: &statres}, nil
}
func (l *AlbumLogic) GetAlbumInfoById(in *album.DetailReq) (*album.DetailResp, error) {
	test := bloom.Bloom.Filter.Test([]byte(fmt.Sprintf("%d", in.AlbumId)))
	if !test {
		return nil, errors.New("专辑不存在")
	}
	fmt.Println("我要往下查了")
	att, err := l.albumInfoDomain.FindAlbumByIdAndUserId(l.ctx, in.AlbumId, in.UserId)
	if err != nil {
		return nil, err
	}
	var res album.DetailResp
	var AlbumAttributeValues []*album.AlbumAttributeValue
	// 查一下属性
	key := fmt.Sprintf("albumInfo:%d", in.AlbumId)
	err = l.svcCtx.Cache.Get(key, &res)
	if res.Id != 0 && err == nil {
		return &res, nil
	}
	// 加分布式锁的原因是防止大量redis没有的数据请求进来，导致进入数据库查询，防止数据库压力过大
	// 一直查一个没有的id怎么办，布隆过滤器
	redisLock := redis.NewRedisClient()
	mutex := redisLock.Mutex(key)
	err = mutex.Lock()
	if err != nil {
		logx.Errorf("GetAlbumInfoById mutex error:%v", err)
		return nil, errors.New("获取分布式锁错误")
	}
	attributeValues, err := l.attribute.FindByAid(l.ctx, in.AlbumId)
	if err != nil {
		return nil, err
	}
	for _, attributeValue := range attributeValues {
		// 查询attribute
		fmt.Println("-------------")
		fmt.Println("进入数据库查询")
		attribute, err := l.attribute.FindAttributeById(l.ctx, attributeValue.AttributeId)
		if err != nil {
			return nil, err
		}
		Values, err := l.attribute.FindAttributeValuesById(l.ctx, attributeValue.ValueId)
		if err != nil {
			return nil, err
		}
		albumAttributeValue := album.AlbumAttributeValue{}
		albumAttributeValue.ValueId = Values.Id
		albumAttributeValue.AlbumId = in.AlbumId
		albumAttributeValue.AttributeId = attribute.Id
		albumAttributeValue.AttributeName = attribute.AttributeName
		albumAttributeValue.ValueName = Values.ValueName
		AlbumAttributeValues = append(AlbumAttributeValues, &albumAttributeValue)
	}

	err = copier.Copy(&res, att)
	if err != nil {
		return nil, err
	}
	res.AlbumAttributeValueList = AlbumAttributeValues
	// 查找播放数
	playStatNum, subscribeStatNum, buyStatNum, commentStatNum, err := l.albumStatDomain.FindByAlbumId(l.ctx, in.AlbumId)
	if err != nil {
		return nil, err
	}
	playNum, _ := strconv.ParseInt(playStatNum, 10, 64)
	subscribeNum, _ := strconv.ParseInt(subscribeStatNum, 10, 64)
	buyNum, _ := strconv.ParseInt(buyStatNum, 10, 64)
	commentNum, _ := strconv.ParseInt(commentStatNum, 10, 64)
	res.PlayStatNum = playNum
	res.SubscribeStatNum = subscribeNum
	res.BuyStatNum = buyNum
	res.CommentStatNum = commentNum
	err = l.svcCtx.Cache.Set(key, &res)
	if err != nil {
		return &res, err
	}
	if ok, err := mutex.Unlock(); !ok || err != nil {
		logx.Errorf("GetAlbumInfoById unloak faild error:%v", err)
		return nil, errors.New("释放分布式锁错误")
	}

	return &res, nil
}

func (l *AlbumLogic) SaveAlbumInfo(in *album.SaveAlbumInfoReq) (*album.SaveAlbumInfoResp, error) {
	// 要先查找专辑名称是否存在 这里为了省事不写了
	var id int64
	var err error
	// 修改后需要删除redis缓存
	err = l.transaction.Action(func(conn db.DBConn) error {
		id, err = l.albumInfoDomain.SaveAlbumInfo(l.ctx, conn, in)
		if err != nil {
			return err
		}
		if in.AlbumId != 0 {
			l.svcCtx.Cache.DelCtx(l.ctx, fmt.Sprintf("albumInfo:%d", in.AlbumId))
			return nil
		}
		err = l.attribute.SaveAlbumInfo(l.ctx, conn, id, in.AlbumAttributeValueVoList)
		if err != nil {
			return err
		}
		err = l.albumStatDomain.SaveAlbumStat(l.ctx, conn, id)
		if err != nil {
			return err
		}
		if err != nil {
			return err
		}
		return nil
	})
	// kafka发送信息
	if in.IsOpen == "1" {
		// 查询专辑详情
		var albumKafka model.AlbumInfo
		att, err := l.albumInfoDomain.FindAlbumByIdAndUserId(l.ctx, id, in.UserId)
		if err != nil {
			return nil, err
		}
		playStatNum, subscribeStatNum, buyStatNum, commentStatNum, err := l.albumStatDomain.FindByAlbumId(l.ctx, id)
		if err != nil {
			return nil, err
		}
		err = copier.Copy(&albumKafka, &att)
		if err != nil {
			return nil, err
		}
		playNum, _ := strconv.ParseInt(playStatNum, 10, 64)
		subscribeNum, _ := strconv.ParseInt(subscribeStatNum, 10, 64)
		buyNum, _ := strconv.ParseInt(buyStatNum, 10, 64)
		commentNum, _ := strconv.ParseInt(commentStatNum, 10, 64)
		albumKafka.PlayStatNum = playNum
		albumKafka.SubscribeStatNum = subscribeNum
		albumKafka.BuyStatNum = buyNum
		albumKafka.CommentStatNum = commentNum
		var num1 float64 = 0.2
		hotSocre := float64(playNum)*num1 + float64(subscribeNum)*0.3 + float64(buyNum)*0.4 + float64(commentNum)*0.1
		//str := fmt.Sprintf("%.2f", hotSocre) //
		albumKafka.HotScore = hotSocre

		// 获取分类信息
		c2id, err := l.albumInfoDomain.FindByCategory3ToC2Id(l.ctx, att.Category3Id)
		albumKafka.Category2Id = c2id
		c3id, err := l.albumInfoDomain.FindByCategory2ToC1d(l.ctx, c2id)
		albumKafka.Category3Id = c3id
		// 查找专辑attribute valueId
		values, err := l.attribute.FindByAid(l.ctx, att.Id)
		if err != nil {
			return nil, err
		}
		err = copier.Copy(albumKafka.AttributeValueIndexList, values)
		if err != nil {
			return nil, err
		}
		// 查找用户信息
		re := ucclient.UserInfoIdReq{}
		re.UserId = in.UserId
		userInfo, err := l.svcCtx.UCLoginRpc.GetUserInfoByUserId(l.ctx, &re)
		if err != nil {
			logx.Errorf("rpc调用用户服务出错%v", err)
		}
		albumKafka.AnnouncerName = userInfo.Nickname
		//	l.wg.Add(1)
		suggest := model.SuggestInfo{}
		args := pinyin.NewArgs()
		chinese := tools.IsChinese(albumKafka.AlbumTitle)
		if chinese {
			// 专辑信息
			suggest.Keyword = []string{albumKafka.AlbumTitle}
			pinys := pinyin.LazyPinyin(albumKafka.AlbumTitle, args)
			pin := tools.RemoveSpaces(pinys)
			suggest.KeywordPinyin = []string{pin}

			args.Style = pinyin.FirstLetter
			pySlice := pinyin.LazyPinyin(albumKafka.AlbumTitle, args)
			s := tools.RemoveSpaces(pySlice)
			suggest.KeywordSequence = []string{s}
			suggest.Id = 1
			suggest.Title = albumKafka.AlbumTitle

		} else {
			// 英文
			suggest.KeywordPinyin = []string{albumKafka.AlbumTitle}
			suggest.KeywordSequence = []string{albumKafka.AlbumTitle}
			suggest.Id = albumKafka.Id
			suggest.Title = albumKafka.AlbumTitle
		}
		// 专辑简介
		chinese = tools.IsChinese(albumKafka.AlbumIntro)
		if chinese {
			suggest.Keyword = append(suggest.Keyword, albumKafka.AlbumIntro)
			pinys := pinyin.LazyPinyin(albumKafka.AlbumIntro, args)
			pin := tools.RemoveSpaces(pinys)
			suggest.KeywordPinyin = append(suggest.KeywordPinyin, pin)
			args.Style = pinyin.FirstLetter
			pySlice := pinyin.LazyPinyin(albumKafka.AlbumIntro, args)
			s := tools.RemoveSpaces(pySlice)
			suggest.KeywordSequence = append(suggest.KeywordSequence, s)
			// 专辑简介
		} else {
			// 英文
			suggest.KeywordPinyin = append(suggest.KeywordPinyin, albumKafka.AlbumIntro)
			suggest.KeywordSequence = append(suggest.KeywordSequence, albumKafka.AlbumIntro)
		}
		// 主播信息
		chinese = tools.IsChinese(userInfo.Nickname)
		if chinese {
			suggest.Keyword = append(suggest.Keyword, userInfo.Nickname)
			pinys := pinyin.LazyPinyin(userInfo.Nickname, args)
			pin := tools.RemoveSpaces(pinys)
			suggest.KeywordPinyin = append(suggest.KeywordPinyin, pin)
			args.Style = pinyin.FirstLetter
			pySlice := pinyin.LazyPinyin(userInfo.Nickname, args)
			s := tools.RemoveSpaces(pySlice)
			suggest.KeywordSequence = append(suggest.KeywordSequence, s)
			// 专辑简介
		} else {
			// 英文
			suggest.KeywordPinyin = append(suggest.KeywordPinyin, userInfo.Nickname)
			suggest.KeywordSequence = append(suggest.KeywordSequence, userInfo.Nickname)
		}
		//l.wg.Add(2)
		go func() {
			fmt.Println("正在推送kafka中")
			err = client.PushV1(&albumKafka)
			if err != nil {
				logx.Error("Kafka push错误------------------")
				logx.Error(err)
				return
			}
			fmt.Println("推送成功")
			//	l.wg.Done()
		}()
		go func() {
			fmt.Println("suggest正在推送kafka中")
			err = client.PushV2ToSuggest(&suggest)
			if err != nil {
				logx.Error("Kafka push错误------------------")
				logx.Error(err)
				return
			}
			fmt.Println("suggest推送成功")
			//l.wg.Done()
		}()
		//	l.wg.Wait()
	}
	return &album.SaveAlbumInfoResp{Id: id}, nil
}
func (l *AlbumLogic) FindUserAllAlbumList(in *album.AlbumListReq) (*album.AlbumListResp, error) {
	albums, err := l.albumInfoDomain.FindAlbumListByUserId(l.ctx, in.UserId)
	if err != nil {
		return nil, err
	}
	var res []*album.Records
	err = copier.Copy(&res, &albums)
	if err != nil {
		return nil, err
	}
	return &album.AlbumListResp{Records: res}, nil

}

func (l *AlbumLogic) FindUserAlbumPage(in *album.FindUserAlbumReq) (*album.FindUserAlbumResp, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 50*time.Second)
	defer cancel()
	albums, err := l.albumInfoDomain.FindAlbumByUserId(ctx, in)
	if err != nil {
		return nil, err
	}
	var res []*album.Records
	err = copier.Copy(&res, &albums)
	if err != nil {
		return nil, err
	}
	for _, r := range res {

		playStatNum, subscribeStatNum, buyStatNum, commentStatNum, err := l.albumStatDomain.FindByAlbumId(ctx, r.Id)
		if err != nil {
			return nil, err
		}
		r.PlayStatNum, _ = strconv.ParseInt(playStatNum, 10, 64)
		r.SubscribeStatNum, _ = strconv.ParseInt(subscribeStatNum, 10, 64)
		r.BuyStatNum, _ = strconv.ParseInt(buyStatNum, 10, 64)
		r.CommentStatNum, _ = strconv.ParseInt(commentStatNum, 10, 64)
	}
	return &album.FindUserAlbumResp{
		Records: res,
	}, nil
}

func (l *AlbumLogic) GetCategoryToAttribute(in *album.GetC1IdToAttributeReq) (*album.GetC1IdToAttributeResp, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 50*time.Second)
	defer cancel()
	id, err := strconv.ParseInt(in.Id, 10, 64)
	if err != nil {
		return nil, err
	}
	atts, err := l.attribute.GetByC1IdToAttribute(ctx, id)
	if err != nil {
		return nil, err
	}
	var res []*album.GetC1IdToAttribute
	for _, att := range atts {
		value, err := l.attribute.GetByC1IdToAttributeValue(ctx, att.Id)
		if err != nil {
			return nil, err
		}
		attribute := album.GetC1IdToAttribute{}
		if value != nil {
			for _, v := range value {
				attValue := album.AttributeValueList{}
				attValue.Id = v.Id
				attValue.CreateTime = v.CreateTime
				attValue.ValueName = v.ValueName
				attribute.AttributeValueList = append(attribute.AttributeValueList, &attValue)
			}
			attribute.Category1Id = id
			attribute.Id = att.Id
			attribute.CreateTime = att.CreateTime
			attribute.AttributeName = att.AttributeName
			res = append(res, &attribute)
		}
	}
	return &album.GetC1IdToAttributeResp{
		GetC1IdToAttributes: res,
	}, nil
}

func (l *AlbumLogic) GetAllCategoryAll(in *album.RegReq) (*album.CategoryReq, error) {
	// todo: add your logic here and delete this line
	// 找到所有的一级分类
	ctx, cancel := context.WithTimeout(context.Background(), 50*time.Second)
	defer cancel()
	category1s, err := l.albumInfoDomain.FindByCategory1(ctx, 0)
	if err != nil {
		return nil, err
	}
	//var res album.CategoryReq
	var resp []*album.CategoryReq
	// 二级分类
	// 三级分类
	for _, category1 := range category1s {
		cates, err := l.GetCategoryIdAndName(ctx, category1.Id, category1.Name)
		if err != nil {
			return nil, err
		}
		category := &album.CategoryReq{}
		err = copier.Copy(&category, &cates)
		if err != nil {
			return nil, err
		}
		//res.CategoryChild = append(res.CategoryChild, category)
		resp = append(resp, category)
	}
	//ret := &res
	//fmt.Print(ret)
	return &album.CategoryReq{
		CategoryChild: resp,
	}, nil
}
func (l *AlbumLogic) GetCategoryIdAndName(ctx context.Context, id int64, name string) (*album.CategoryReq, error) {
	category2s, err := l.albumInfoDomain.FindByCategory2(ctx, id)
	if err != nil {
		return nil, err
	}
	var child []*album.CategoryReq
	for _, category2 := range category2s {
		cate, err := l.GetCategoryIdAndName3(ctx, category2.Id, category2.Name)
		if err != nil {
			return nil, err
		}
		if cate != nil {
			var ablumCate album.CategoryReq
			err = copier.Copy(&ablumCate, &cate)
			if err != nil {
				return nil, err
			}
			child = append(child, &ablumCate)
		}
	}
	return &album.CategoryReq{
		CategoryId:    id,
		CategoryName:  name,
		CategoryChild: child,
	}, nil
}
func (l *AlbumLogic) GetCategoryIdAndName3(ctx context.Context, id int64, name string) (*album.CategoryReq, error) {
	category3s, err := l.albumInfoDomain.FindByCategory3(ctx, id)
	if err != nil {
		return nil, err
	}
	var child []*album.CategoryReq
	for _, category3 := range category3s {
		cate, err := l.GetCategoryIdAndName(ctx, category3.Id, category3.Name)
		if err != nil {
			return nil, err
		}
		if cate != nil {
			var ablumCate album.CategoryReq
			err = copier.Copy(&ablumCate, &cate)
			if err != nil {
				return nil, err
			}
			child = append(child, &ablumCate)
		}
	}
	return &album.CategoryReq{
		CategoryId:    id,
		CategoryName:  name,
		CategoryChild: child,
	}, nil
}

func (l *AlbumLogic) RemoteAlbumInfo(in *album.RemoteReq) (*album.RemoteResp, error) {
	var err error
	err = l.transaction.Action(func(conn db.DBConn) error {
		err = l.albumInfoDomain.DeleteAlbumInfo(l.ctx, conn, in)
		if err != nil {
			return err
		}
		err = l.attribute.DeleteAlbumAttributeValues(l.ctx, conn, in.AlbumId)
		if err != nil {
			return err
		}
		return nil
	})
	return &album.RemoteResp{}, err
}

func (l *AlbumLogic) SaveTrackInfo(in *album.SaveTrackReq) (*album.SaveTrackResp, error) {
	var trackId int64
	var err error

	l.transaction.Action(func(conn db.DBConn) error {
		trackId, err = l.trackInfoDomain.SaveTrackInfo(l.ctx, conn, in)
		if err != nil {
			return err
		}

		err = l.trackStatDomain.SaveTrackStat(l.ctx, conn, trackId, in)
		if err != nil {
			return err
		}
		return nil
	})
	return &album.SaveTrackResp{Id: trackId}, nil
}
func (l *AlbumLogic) InitBloom() {
	l.albumInfoDomain.InitBloom()
}
func (l *AlbumLogic) FindUserTrackPage(in *album.FindUserTrackPageReq) (*album.FindUserTrackPageResp, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 50*time.Second)
	defer cancel()
	tracks, err := l.trackInfoDomain.FindAlbumByUserId(ctx, in)
	if err != nil {
		return nil, err
	}
	var res []*album.TrackRecords
	err = copier.Copy(&res, &tracks)
	if err != nil {
		return nil, err
	}
	for _, r := range res {
		playStatNum, collectStatNum, praiseStatNum, commentStatNum, err := l.trackStatDomain.FindByTrackId(ctx, r.Id)
		if err != nil {
			return nil, err
		}
		r.PlayStatNum, _ = strconv.ParseInt(playStatNum, 10, 64)
		r.CollectStatNum, _ = strconv.ParseInt(collectStatNum, 10, 64)
		r.PraiseStatNum, _ = strconv.ParseInt(praiseStatNum, 10, 64)
		r.CommentStatNum, _ = strconv.ParseInt(commentStatNum, 10, 64)
	}
	return &album.FindUserTrackPageResp{
		TrackRecords: res,
	}, nil
}

func (l *AlbumLogic) GetTrackInfoById(in *album.TrackInfoReq) (*album.TrackInfoResp, error) {
	att, err := l.trackInfoDomain.FindTrackByIdAndUserId(l.ctx, in.TrackId)
	if err != nil {
		return nil, err
	}
	var res album.TrackInfoResp
	// 查一下属性
	err = copier.Copy(&res, att)
	if err != nil {
		return nil, err
	}
	return &res, nil
}

func (l *AlbumLogic) RemoveTrackInfo(in *album.RemoveTrackInfoReq) (*album.RemoveTrackInfoResp, error) {
	var err error
	err = l.transaction.Action(func(conn db.DBConn) error {
		err = l.trackInfoDomain.DeleteTrackInfo(l.ctx, conn, in)
		if err != nil {
			return err
		}
		err = l.trackStatDomain.DeleteTrackStat(l.ctx, conn, in.TrackId)
		if err != nil {
			return err
		}
		return nil
	})
	return &album.RemoveTrackInfoResp{}, err
}
func (l *AlbumLogic) BatchSaveEs() error {
	// 找到所有专辑
	albums, err := l.albumInfoDomain.GetAllCategoryList(l.ctx)
	if err != nil {
		return err
	}
	for _, album := range albums {
		// kafka发送信息
		// 查询专辑详情
		var albumKafka model.AlbumInfo
		att, err := l.albumInfoDomain.FindAlbumByIdAndUserId(l.ctx, album.Id, album.UserId)
		if err != nil && err != gorm.ErrRecordNotFound {
			return err
		}
		playStatNum, subscribeStatNum, buyStatNum, commentStatNum, err := l.albumStatDomain.FindByAlbumId(l.ctx, album.Id)
		if err != nil {
			return err
		}
		err = copier.Copy(&albumKafka, &att)
		if err != nil {
			return err
		}
		num := rand.Intn(1000)
		num64 := int64(num)
		playNum, _ := strconv.ParseInt(playStatNum, 10, 64)
		playNum = num64
		subscribeNum, _ := strconv.ParseInt(subscribeStatNum, 10, 64)
		subscribeNum = num64
		buyNum, _ := strconv.ParseInt(buyStatNum, 10, 64)
		buyNum = num64
		commentNum, _ := strconv.ParseInt(commentStatNum, 10, 64)
		commentNum = num64
		albumKafka.PlayStatNum = playNum
		albumKafka.SubscribeStatNum = subscribeNum
		albumKafka.BuyStatNum = buyNum
		albumKafka.CommentStatNum = commentNum
		var num1 float64 = 0.2
		hotSocre := float64(playNum)*num1 + float64(subscribeNum)*0.3 + float64(buyNum)*0.4 + float64(commentNum)*0.1
		//str := fmt.Sprintf("%.2f", hotSocre) //
		albumKafka.HotScore = hotSocre
		// 获取分类信息
		c2id, err := l.albumInfoDomain.FindByCategory3ToC2Id(l.ctx, att.Category3Id)
		albumKafka.Category2Id = c2id
		c1id, err := l.albumInfoDomain.FindByCategory2ToC1d(l.ctx, c2id)
		albumKafka.Category1Id = c1id
		values, err := l.attribute.FindByAid(l.ctx, att.Id)
		if err != nil {
			return err
		}
		if values == nil {
			continue
		}
		err = copier.Copy(&albumKafka.AttributeValueIndexList, &values)
		if err != nil {
			return err
		}
		// 查找用户信息
		re := ucclient.UserInfoIdReq{}
		re.UserId = album.UserId
		userInfo, err := l.svcCtx.UCLoginRpc.GetUserInfoByUserId(l.ctx, &re)
		if err != nil {
			logx.Errorf("rpc调用用户服务出错%v", err)
		}
		albumKafka.AnnouncerName = userInfo.Nickname
		// 专辑搜索补全
		suggest := model.SuggestInfo{}
		args := pinyin.NewArgs()
		chinese := tools.IsChinese(albumKafka.AlbumTitle)
		if chinese {
			// 专辑信息
			suggest.Keyword = []string{albumKafka.AlbumTitle}
			pinys := pinyin.LazyPinyin(albumKafka.AlbumTitle, args)
			pin := tools.RemoveSpaces(pinys)
			suggest.KeywordPinyin = []string{pin}

			args.Style = pinyin.FirstLetter
			pySlice := pinyin.LazyPinyin(albumKafka.AlbumTitle, args)
			s := tools.RemoveSpaces(pySlice)
			suggest.KeywordSequence = []string{s}
			suggest.Id = 1
			suggest.Title = albumKafka.AlbumTitle

		} else {
			// 英文
			suggest.KeywordPinyin = []string{albumKafka.AlbumTitle}
			suggest.KeywordSequence = []string{albumKafka.AlbumTitle}
			suggest.Id = albumKafka.Id
			suggest.Title = albumKafka.AlbumTitle
		}
		// 专辑简介
		chinese = tools.IsChinese(albumKafka.AlbumIntro)
		if chinese {
			suggest.Keyword = append(suggest.Keyword, albumKafka.AlbumIntro)
			pinys := pinyin.LazyPinyin(albumKafka.AlbumIntro, args)
			pin := tools.RemoveSpaces(pinys)
			suggest.KeywordPinyin = append(suggest.KeywordPinyin, pin)
			args.Style = pinyin.FirstLetter
			pySlice := pinyin.LazyPinyin(albumKafka.AlbumIntro, args)
			s := tools.RemoveSpaces(pySlice)
			suggest.KeywordSequence = append(suggest.KeywordSequence, s)
			// 专辑简介
		} else {
			// 英文
			suggest.KeywordPinyin = append(suggest.KeywordPinyin, albumKafka.AlbumIntro)
			suggest.KeywordSequence = append(suggest.KeywordSequence, albumKafka.AlbumIntro)
		}
		// 主播信息
		chinese = tools.IsChinese(userInfo.Nickname)
		if chinese {
			suggest.Keyword = append(suggest.Keyword, userInfo.Nickname)
			pinys := pinyin.LazyPinyin(userInfo.Nickname, args)
			pin := tools.RemoveSpaces(pinys)
			suggest.KeywordPinyin = append(suggest.KeywordPinyin, pin)
			args.Style = pinyin.FirstLetter
			pySlice := pinyin.LazyPinyin(userInfo.Nickname, args)
			s := tools.RemoveSpaces(pySlice)
			suggest.KeywordSequence = append(suggest.KeywordSequence, s)
			// 专辑简介
		} else {
			// 英文
			suggest.KeywordPinyin = append(suggest.KeywordPinyin, userInfo.Nickname)
			suggest.KeywordSequence = append(suggest.KeywordSequence, userInfo.Nickname)
		}
		//	l.wg.Add(2)
		go func() {
			err1 := client.Push(client.KafKaClient, &albumKafka)
			if err1 != nil {
				logx.Error("Kafka push错误------------------")
				logx.Error(err1)
				return
			}
			fmt.Println("推送kafka成功")
			//	l.wg.Done()
		}()
		go func() {
			fmt.Println("suggest正在推送kafka中")
			err = client.PushV2ToSuggest(&suggest)
			if err != nil {
				logx.Error("Kafka push错误------------------")
				logx.Error(err)
				return
			}
			fmt.Println("suggest推送成功")
			//	l.wg.Done()
		}()
		//	l.wg.Wait()
	}

	fmt.Println("全部插入es成功")
	return nil
}

func (l *AlbumLogic) GetCategory3ListByCategory1Id(in *album.GetCategory3ListByCategory1IdReq) (*album.GetCategory3ListByCategory1IdResp, error) {
	// 根据1级分类先查找2级
	// 这个是只差一级的
	c2s, err := l.albumInfoDomain.FindByCategory2ByOrder(l.ctx, in.Category1Id)
	if err != nil {
		return nil, err
	}
	var res []*album.CategoryInfo
	// 视频上需要再建一个切片对象，然后一起追加上去
	//var re []*album.CategoryInfo
	// 再根据2及分类查找三级返回
	for _, c2 := range c2s {
		c3s, err := l.albumInfoDomain.FindByCategory3To8(l.ctx, c2.Id)
		if err != nil {
			return nil, err
		}
		err = copier.Copy(&res, &c3s)
		if err != nil {
			return nil, err
		}
	}
	return &album.GetCategory3ListByCategory1IdResp{CategoryInfo: res}, nil
}

func (l *AlbumLogic) GetCategoryChannel(in *album.CategoryChannelReq) (*album.CategoryChannelResp, error) {
	// 根据1级分类先查找2级
	// 这个是只差一级的
	c2s, err := l.albumInfoDomain.FindByCategory2ByOrder(l.ctx, in.Category1Id)
	if err != nil {
		return nil, err
	}
	//var baseCategory3s []*album.BaseCategory3
	var categorys []*album.CategoryChannel
	// 视频上需要再建一个切片对象，然后一起追加上去
	//var re []*album.CategoryInfo
	// 再根据2及分类查找三级返回
	for _, c2 := range c2s {
		// 现在是3级
		c3s, err := l.albumInfoDomain.FindByCategory3To8Desc(l.ctx, c2.Id)
		if err != nil {
			return nil, err
		}

		//var keyWords []string
		// 根据3级调用search服务
		for _, c3 := range c3s {
			category := album.CategoryChannel{}
			alist := []*album.CategoryAlbumInfo{}
			keyWord := strconv.FormatInt(c3.Id, 10)
			baseCategory3 := album.BaseCategory3{}
			// 专辑list
			//keyWords = append(keyWords, keyWord)
			// 调用search服务
			req := search.GetAlbumChannelReq{}
			req.KeyWord = keyWord
			albums, err := l.svcCtx.SearchRpc.GetAlbumChannel(l.ctx, &req)
			if err != nil {
				logx.Errorf("rpc 调用search 服务失败 error: %v", err)
				return nil, nil
			}
			err = copier.Copy(&baseCategory3, &c3)
			if err != nil {
				return nil, err
			}
			err = copier.Copy(&alist, &albums.SearchAlbumInfo)
			if err != nil {
				return nil, err
			}
			category.List = alist
			category.BaseCategory3 = &baseCategory3
			categorys = append(categorys, &category)
		}
	}
	return &album.CategoryChannelResp{Category: categorys}, nil
}

func (l *AlbumLogic) GetBaseCategoryList3(in *album.GetBaseCategoryList3Req) (*album.GetBaseCategoryList3Resp, error) {
	// todo: add your logic here and delete this line
	// 找到所有的一级分类
	var res album.GetBaseCategoryList3Resp
	res.CategoryId = in.Category1Id
	ctx, cancel := context.WithTimeout(context.Background(), 50*time.Second)
	defer cancel()
	category1, err := l.albumInfoDomain.FindByCategory1ById(ctx, in.Category1Id)
	if err != nil {
		return nil, err
	}
	// 这里找到一个第一级别的
	res.CategoryId = category1.Id
	res.CategoryName = category1.Name
	//var resp []*album.GetBaseCategoryList3Resp
	// 二级分类
	// 三级分类
	cates, err := l.GetCategoryIdAndNameList(ctx, category1.Id, category1.Name)
	if err != nil {
		return nil, err
	}
	res.CategoryChild = cates
	return &res, nil
}
func (l *AlbumLogic) GetCategoryIdAndNameList(ctx context.Context, id int64, name string) (res []*album.GetBaseCategoryList3Resp, err error) {
	category2s, err := l.albumInfoDomain.FindByCategory2(ctx, id)
	if err != nil {
		return nil, err
	}
	for _, category2 := range category2s {
		child := album.GetBaseCategoryList3Resp{}
		cate3, err := l.GetCategoryIdAndName3List(ctx, category2.Id, category2.Name)
		if err != nil {
			return nil, err
		}
		if cate3 != nil {
			var ablumCate []*album.GetBaseCategoryList3Resp
			err = copier.Copy(&ablumCate, &cate3)
			if err != nil {
				return nil, err
			}
			child.CategoryId = category2.Id
			child.CategoryName = category2.Name
			child.CategoryChild = ablumCate
			res = append(res, &child)
		}
	}
	return res, nil
}
func (l *AlbumLogic) GetCategoryIdAndName3List(ctx context.Context, id int64, name string) ([]*album.GetBaseCategoryList3Resp, error) {
	category3s, err := l.albumInfoDomain.FindByCategory3(ctx, id)
	if err != nil {
		return nil, err
	}
	var res []*album.GetBaseCategoryList3Resp
	for _, category3 := range category3s {
		child := album.GetBaseCategoryList3Resp{}
		if category3 != nil {
			child.CategoryId = category3.Id
			child.CategoryName = category3.Name
			child.CategoryChild = nil
			res = append(res, &child)
		}
	}

	return res, nil
}

func (l *AlbumLogic) SearchAlbumInfo(in *album.AlbumInfoReq) (*album.AlbumInfoResp, error) {
	var req search.AlbumInfoReq
	err := copier.Copy(&req, &in)
	if err != nil {
		return nil, err
	}
	info, err := l.svcCtx.SearchRpc.SearchAlbumInfo(l.ctx, &req)
	if err != nil {
		logx.Errorf("rpc 调用SearchAlbumInfo 失败 error: %v", err)
		return nil, err
	}
	res := album.AlbumInfoResp{}
	err = copier.Copy(&res, &info)
	if err != nil {
		return nil, err
	}
	return &res, nil
}

func (l *AlbumLogic) KeyWord(in *album.KeywordReq) (*album.KeywordResp, error) {
	var req search.KeywordReq
	req.Keyword = in.Keyword
	words, err := l.svcCtx.SearchRpc.KeyWord(l.ctx, &req)
	if err != nil {
		logx.Errorf("rpc 调用keyword失败 error: %v", err)
		return nil, err
	}
	return &album.KeywordResp{Keywords: words.Keywords}, nil
}

func (l *AlbumLogic) FindAlbumTrackPage(in *album.FindTrackReq) (*album.FindTrackResp, error) {
	// 查询track表和stat表
	att, err := l.albumInfoDomain.FindAlbumById(l.ctx, in.AlbumId)
	if err != nil {
		return nil, err
	}
	ctx, cancel := context.WithTimeout(context.Background(), 50*time.Second)
	defer cancel()
	tracks, current, Size, total, pages, err := l.trackInfoDomain.FindTrackByAlbumId(ctx, in.AlbumId, in.PageNo, in.PageSize)
	if err != nil {
		return nil, err
	}
	var res []*album.Track
	for _, track := range tracks {
		tck := album.Track{}
		err = copier.Copy(&tck, &track)
		if err != nil {
			return nil, err
		}
		tck.TrackId = track.Id
		res = append(res, &tck)
	}

	//	还需要判断用户是不是vip
	userInfo, err := l.svcCtx.UCLoginRpc.GetUserInfoByUserId(l.ctx, &login.UserInfoIdReq{UserId: in.UserId})
	if err != nil {
		return nil, err
	}
	for _, r := range res {
		if in.UserId == 0 {
			if att.PayType == "0103" || att.PayType == "0102" {
				if r.OrderNum < att.TracksForFree {
					r.IsShowPaidMark = true
				} else {
					r.IsShowPaidMark = false
				}
			}
		} else {
			// 用户有登录
			var ureq login.FindUserPayAlbumReq
			ureq.UserId = in.UserId
			ureq.AlbumId = in.AlbumId
			payAlbum, err := l.svcCtx.UCLoginRpc.FindUserPayAlbum(l.ctx, &ureq)
			if err != nil {
				return nil, err
			}
			if userInfo.IsVip == 1 && tools.IsVipExpAfter(userInfo.VipExpireTime) {
				if att.PayType == "0102" {
					r.IsShowPaidMark = false
				} else if att.PayType == "0103" {
					if payAlbum.AlbumId == in.AlbumId {
						r.IsShowPaidMark = false
					} else if payAlbum.TrackId != nil {
						// 这里就for循环了一次
						for _, id := range payAlbum.TrackId {
							if r.OrderNum < att.TracksForFree {
								if r.TrackId == id {
									r.IsShowPaidMark = false
								} else {
									r.IsShowPaidMark = false
								}

							} else {
								if r.TrackId == id {
									r.IsShowPaidMark = false
								} else {
									r.IsShowPaidMark = true
								}

							}
						}
					} else {
						if r.OrderNum < att.TracksForFree {
							r.IsShowPaidMark = false
						} else {
							r.IsShowPaidMark = true
						}
					}
				} else if att.PayType == "0101" {
					r.IsShowPaidMark = false
				}
			} else {
				if payAlbum.AlbumId == in.AlbumId {
					r.IsShowPaidMark = false
				} else if payAlbum.TrackId != nil {
					// 这里就for循环了一次
					for _, id := range payAlbum.TrackId {
						if r.OrderNum < att.TracksForFree {
							if r.TrackId == id {
								r.IsShowPaidMark = false
							} else {
								r.IsShowPaidMark = false
							}

						} else {
							if r.TrackId == id {
								r.IsShowPaidMark = false
							} else {
								r.IsShowPaidMark = true
							}

						}
					}
				} else {
					if r.OrderNum < att.TracksForFree {
						r.IsShowPaidMark = false
					} else {
						r.IsShowPaidMark = true
					}
				}
			}
		}

		playStatNum, collectStatNum, praiseStatNUm, commentStatNum, err := l.trackStatDomain.FindByTrackId(l.ctx, r.TrackId)
		if err != nil {
			return nil, err
		}
		if err != nil {
			return nil, err
		}
		r.PlayStatNum, _ = strconv.ParseInt(playStatNum, 10, 64)
		r.CollectStatNum, _ = strconv.ParseInt(collectStatNum, 10, 64)
		r.PraiseStatNUm, _ = strconv.ParseInt(praiseStatNUm, 10, 64)
		r.CommentStatNum, _ = strconv.ParseInt(commentStatNum, 10, 64)
	}
	return &album.FindTrackResp{
		Records: res,
		Current: current,
		Pages:   pages,
		Total:   total,
		Size:    Size,
	}, nil
}

func (l *AlbumLogic) UpdateListenProcess(in *album.UpdateListenReq) (*album.UpdateListenResp, error) {
	// 使用mongodb先查询进度是否存在
	process, err := l.processDomain.FindProcess(l.ctx, in.UserId, in.AlbumId, in.TrackId)
	if err != nil {
		return nil, err
	}
	if process.AlbumId == 0 {
		// 不存在插入
		err = l.processDomain.Create(l.ctx, in.UserId, in.AlbumId, in.TrackId, in.BreakSecond)
		if err != nil {
			return nil, err
		}
	} else {
		// 存在则更新
		err = l.processDomain.Update(l.ctx, in.UserId, in.AlbumId, in.TrackId, in.BreakSecond)
		if err != nil {
			return nil, err
		}
	}
	pro := model_redis.KafkaAlbumAndTrackPlaySum{
		BusinessNo: uuid.New().String(),
		UserId:     in.UserId,
		TrackId:    in.TrackId,
		AlbumId:    in.AlbumId,
		StatType:   "playStatNum",
		Count:      1,
	}

	// 更新播放次数
	go func() {
		// TODO:再加一层用户一天只加一次播放量
		ukey := "user:track" + time.Now().Format(layout) + ":" + fmt.Sprintf("%d", pro.TrackId)
		ok, err := l.redisClient.Client.GetBit(context.Background(), ukey, 1).Result()
		if err != nil {
			return
		}
		if ok == 1 {
			return
		} else {
			// 更新专辑音频播放量
			err = l.trackStatDomain.UpdateTrackNum(context.Background(), in.AlbumId, in.TrackId, pro.StatType, pro.Count)
			fmt.Println("正在推送kafka中")
			err = client.PushToProcess(&pro)
			if err != nil {
				logx.Error("Kafka push错误------------------")
				logx.Error(err)
				return
			}
			fmt.Println("推送成功")
			_, err := l.redisClient.Client.SetBit(context.Background(), ukey, 1, 1).Result()
			if err != nil {
				return
			}
		}
	}()
	// 更新redis里和es
	// 记录专辑与声音同一个用户同一个声音每天只记录一次播放量 使用一个BusinessNo 使用uuid生成cd区分业务
	return &album.UpdateListenResp{}, nil
}

func (l *AlbumLogic) GetLatelyTack(in *album.GetLatelyTackReq) (*album.GetLatelyTackResp, error) {
	process, err := l.processDomain.FindProcessTo1(l.ctx, in.UserId)
	res := &album.GetLatelyTackResp{}
	err = copier.Copy(&res, &process)
	if err != nil {
		return nil, err
	}
	//res.UserId = process.UserId
	//res.AlbumId = process.AlbumId
	//res.TrackId = process.TrackId
	//res.BreakSecond = process.BreakSecond
	return res, nil
}

func (l *AlbumLogic) GetTrackStatVo(in *album.GetTrackStatVoReq) (*album.GetTrackStatVoResp, error) {
	playStatNum, collectStatNum, praiseStatNum, commentStatNum, err := l.trackStatDomain.FindByTrackId(l.ctx, in.TrackId)
	if err != nil {
		return nil, err
	}
	var res album.GetTrackStatVoResp
	res.PlayStatNum, _ = strconv.ParseInt(playStatNum, 10, 64)
	res.CollectStatNum, _ = strconv.ParseInt(collectStatNum, 10, 64)
	res.PraiseStatNum, _ = strconv.ParseInt(praiseStatNum, 10, 64)
	res.CommentStatNum, _ = strconv.ParseInt(commentStatNum, 10, 64)
	return &res, nil
}

func (l *AlbumLogic) FindUserTrackPaidList(in *album.FindUserTrackPaidListReq) (*album.FindUserTrackPaidListResp, error) {
	// 获取比当前大的编号
	ts, aid, err := l.trackInfoDomain.FindGeTrack(l.ctx, in.TrackId)
	if err != nil {
		return nil, err
	}
	// 获取用户已经购买过的声音
	var ureq login.GetUserPaIdTrackReq
	ureq.UserId = in.UserId
	ureq.TrackId = in.TrackId
	ureq.AlbumId = aid
	var trackList []*album.TrackSetting
	uresp, err := l.svcCtx.UCLoginRpc.GetUserPaIdTrack(l.ctx, &ureq)
	if err != nil {
		logx.Error("l.svcCtx.UCLoginRpc.GetUserPaIdTrack error")
		return nil, err
	}
	var noPaidTracks int64
	// 查找一下声音的详情
	albumInfo, err := l.albumInfoDomain.FindAlbumById(l.ctx, aid)
	if err != nil {
		return nil, err
	}
	if uresp.AlbumId != 0 {
		for _, tr := range ts {
			for _, re := range uresp.TrackSettingInterface {
				if tr.Id == re.TrackId {
					continue
				} else {
					noPaidTracks++
				}
			}
		}
	} else if uresp.TrackSettingInterface == nil {
		noPaidTracks = 50
	}
	if noPaidTracks >= 0 {
		price, _ := strconv.ParseFloat(albumInfo.Price, 32)
		track := album.TrackSetting{}
		track.TrackCount = 0
		track.Name = "本集"
		track.Price = float32(price)
		trackList = append(trackList, &track)
	}
	if noPaidTracks > 10 {
		var count int64
		for _, tr := range ts[:10] {
			if uresp.TrackSettingInterface != nil {
				for _, re := range uresp.TrackSettingInterface {
					if tr.Id != re.TrackId {
						count++
					}

				}
			} else {
				count = 10
			}

		}
		price, _ := strconv.ParseFloat(albumInfo.Price, 32)
		track := album.TrackSetting{}
		track.TrackCount = count
		track.Name = fmt.Sprintf("后%d集", count)
		track.Price = float32(price) * float32(count)
		trackList = append(trackList, &track)
	}
	if noPaidTracks > 20 {
		var count int64
		for _, tr := range ts[:20] {
			if uresp.TrackSettingInterface != nil {
				for _, re := range uresp.TrackSettingInterface {
					if tr.Id != re.TrackId {
						count++
					}
				}
			} else {
				count = 20
			}
		}
		price, _ := strconv.ParseFloat(albumInfo.Price, 32)
		track := album.TrackSetting{}
		track.TrackCount = count
		track.Name = fmt.Sprintf("后%d集", count)
		track.Price = float32(price) * float32(count)
		trackList = append(trackList, &track)
	}
	if noPaidTracks > 30 {
		var count int64
		for _, tr := range ts[:30] {
			if uresp.TrackSettingInterface != nil {
				for _, re := range uresp.TrackSettingInterface {
					if tr.Id != re.TrackId {
						count++
					}
				}
			} else {
				count = 30
			}
		}
		price, _ := strconv.ParseFloat(albumInfo.Price, 32)
		track := album.TrackSetting{}
		track.TrackCount = count
		track.Name = fmt.Sprintf("后%d集", count)
		track.Price = float32(price) * float32(count)
		trackList = append(trackList, &track)
	}
	if noPaidTracks >= 50 {
		var count int64
		for _, tr := range ts[:50] {
			if uresp.TrackSettingInterface != nil {
				for _, re := range uresp.TrackSettingInterface {
					if tr.Id != re.TrackId {
						count++
					}
				}
			} else {
				count = 50
			}
		}
		price, _ := strconv.ParseFloat(albumInfo.Price, 32)
		track := album.TrackSetting{}
		track.TrackCount = count
		track.Name = fmt.Sprintf("后%d集", count)
		track.Price = float32(price) * float32(count)
		trackList = append(trackList, &track)
	}
	track := album.TrackSetting{}
	track.Name = "超级会员免费"
	track.Price = float32(15)
	trackList = append(trackList, &track)
	return &album.FindUserTrackPaidListResp{TrackSettingInterface: trackList}, nil
}

func (l *AlbumLogic) GetSubmitOrderInfo(in *album.GetSubmitOrderInfoReq) (*album.GetSubmitOrderInfoResp, error) {
	userInfo, err := l.svcCtx.UCLoginRpc.GetUserInfoByUserId(l.ctx, &ucclient.UserInfoIdReq{UserId: in.UserId})
	if err != nil {
		return nil, err
	}
	var deratePrice float32
	var price float64
	var discount float64
	// 判断用户购买的是什么
	var res album.GetSubmitOrderInfoResp
	var orderDetailList []*album.OrderDetailVo
	var orderDetail album.OrderDetailVo
	var orderDerateList []*album.OrderDerate
	var orderDerate album.OrderDerate
	if in.ItemType == "1001" {
		// 购买的整张专辑
		albumInfo, err := l.albumInfoDomain.FindAlbumById(l.ctx, in.ItemId)
		if err != nil {
			return nil, err
		}
		// 计算打折信息
		price, err = strconv.ParseFloat(albumInfo.Price, 64)
		if err != nil {
			return nil, err
		}
		discount, err = strconv.ParseFloat(albumInfo.Discount, 64)
		if err != nil {
			return nil, err
		}
		// 打折后的前
		deratePrice = float32(price)
		if discount != -1 {
			price = price * discount
		}
		// 再判断是不是vip付费
		if albumInfo.PayType == "0103" {
			if userInfo.IsVip == 1 {
				vipDiscount, err := strconv.ParseFloat(albumInfo.Discount, 32)
				if err != nil {
					return nil, err
				}
				price = price * vipDiscount
			}
		}
		orderDetail.ItemId = in.ItemId
		orderDetail.ItemName = albumInfo.AlbumTitle
		orderDetail.ItemPrice = int64(price)
		orderDetail.ItemUrl = albumInfo.CoverUrl
		orderDetailList = append(orderDetailList, &orderDetail)
		orderDerate.DerateType = in.ItemType
		orderDerate.DerateAmount = int64(deratePrice)
		orderDerateList = append(orderDerateList, &orderDerate)
	} else if in.ItemType == "1002" {
		// 买的单个音频，单个音频传入的是id 往后count个个数
		//ts, err := l.trackInfoDomain.FindTrackInCount(l.ctx, in.ItemId, in.TrackCount)
		//if err != nil {
		//	return nil, err
		//}

		// 判断用户是否购买了
		//docker run -itd -p 10001:10001 -p 10002:10002 -p 10003:10003 -p 10004:10004 -p 10005:10005 -p 10006:10006 -p 10007:10007 --name ubuntu-ChatGpt ubuntu /bin/bash
	} else if in.ItemType == "1003" {
		// 买的超级会员
		vipServerConfigs, err := l.svcCtx.UCLoginRpc.FindAllServiceConfig(l.ctx, &ucclient.FindAllServiceConfigReq{})
		if err != nil {
			return nil, err
		}
		for _, vipServerConfig := range vipServerConfigs.VipServiceConfig {
			if in.ItemId == vipServerConfig.Id {
				price, _ = strconv.ParseFloat(vipServerConfig.Price, 64)
				deratePrice = float32(price)
				discount, _ = strconv.ParseFloat(vipServerConfig.DiscountPrice, 64)
				price = price * discount
				orderDetail.ItemId = in.ItemId
				orderDetail.ItemName = vipServerConfig.Name
				orderDetail.ItemPrice = int64(price)
				orderDetail.ItemUrl = vipServerConfig.ImageUrl
				orderDetailList = append(orderDetailList, &orderDetail)
				orderDerate.DerateType = in.ItemType
				orderDerate.DerateAmount = int64(deratePrice)
				orderDerateList = append(orderDerateList, &orderDerate)
			}
		}

	}
	res.ItemType = in.ItemType
	res.DerateAmount = int64(deratePrice)
	res.OrderAmount = int64(price)
	res.OriginalAmount = int64(price)
	res.OrderDerateVoList = orderDerateList
	res.OrderDetailVoList = orderDetailList
	res.Sign = userInfo.Nickname
	res.PayWay = ""
	return &res, nil
}

func (l *AlbumLogic) SubmitOrder(in *album.SubmitOrderReq) (*album.SubmitOrderResp, error) {
	orderInfoVo, sign,err := l.confirmOrder(in)
	if err != nil {
		return nil, err
	}
	orderInfoVo.PayWay = ""
	orderInfoVo.Sign = ""
	data, _ := json.Marshal(&orderInfoVo)
	ok := tools.VerifyMD5Signature(data,sign)
	if !ok{
		return nil,errors.New("签名校验不通过")
	}
	tradeNo :=orderInfoVo.TradeNo
	tradeNoKey := fmt.Sprintf("user:trade:%d", in.UserId)
	// 使用lua脚本保证线程安全
	script := `if(redis.call('get', KEYS[1]) == ARGV[1]) then return redis.call('del', KEYS[1]) else return 0 end`
	result, err := l.redisClient.Client.Eval(l.ctx, script, []string{tradeNoKey}, []string{tradeNo}).Result()
	if err != nil {
		return nil,err
	}
	if result==nil{
		return nil,errors.New("支付重复提交")
	}
	if orderInfoVo.PayWay =="1103"{
		// 锁定账户余额 mutex
		// 账户信息
		// 扣减
		//l.svcCtx.UCLoginRpc.GetAccountBalance()
	}
}

// 订单配置
func (l *AlbumLogic) confirmOrder(in *album.SubmitOrderReq) (*album.GetSubmitOrderInfoResp, string, error) {
	var orderDerateVoList []*album.OrderDerate
	var orderDetailVoList []*album.OrderDetailVo
	var orderInfoVo album.GetSubmitOrderInfoResp
	var finalPrice float32
	var deratePrice float32
	var originalPrice float32
	// 用户购买的是整个专辑
	if in.ItemType == "1001" {
		// 获取专辑信息
		var aid int64
		for _, orderDetail := range in.OrderDetailVoList {
			aid = orderDetail.ItemId
			break
		}
		albumInfo, err := l.albumInfoDomain.FindAlbumById(l.ctx, aid)
		if err != nil {
			return nil,"", err
		}
		// 判断用户是不是会员
		userInfo, err := l.svcCtx.UCLoginRpc.GetUserInfoByUserId(l.ctx, &ucclient.UserInfoIdReq{UserId: in.UserId})
		if err != nil {
			return nil,,"", err
		}
		price, _ := strconv.ParseFloat(albumInfo.Price, 64)
		if userInfo.IsVip == 0 {
			// 判断专辑是否可以打折 -1为不打折
			deratePrice = float32(price)
			if albumInfo.Discount != "-1" {
				discount, _ := strconv.ParseFloat(albumInfo.Discount, 64)
				deratePrice = float32(price * discount)
			}
			finalPrice = deratePrice
		} else {
			deratePrice = float32(price)
			if albumInfo.Discount != "-1" {
				discount, _ := strconv.ParseFloat(albumInfo.Discount, 64)
				vipDiscount, _ := strconv.ParseFloat(albumInfo.VipDiscount, 64)
				deratePrice = float32((price * discount) * vipDiscount)

			}
			finalPrice = deratePrice
		}
		// 订单明细
		orderDetailVo := &album.OrderDetailVo{}
		orderDetailVo.ItemUrl = albumInfo.CoverUrl
		orderDetailVo.ItemId = aid
		orderDetailVo.ItemPrice = int64(price)
		orderDetailVo.ItemName = albumInfo.AlbumTitle
		orderDetailVoList = append(orderDetailVoList, orderDetailVo)
		if deratePrice != 0 {
			orderDerate := &album.OrderDerate{
				DerateAmount: int64(deratePrice),
				DerateType:   in.ItemType,
			}
			orderDerateVoList = append(orderDerateVoList, orderDerate)
		}
	} else if in.ItemType == "1002" {
		// 购买多个声音
	} else if in.ItemType == "1003" {

	}
	// 生成一个tradeNo 防止被订单重复提交
	tradeNoKey := fmt.Sprintf("user:trade:%d", in.UserId)
	tradeNo := fmt.Sprintf("user:trade:%s", uuid.New().String())
	ctx := context.Background()
	_, err := l.redisClient.Client.Set(ctx, tradeNoKey, tradeNo, 0).Result()
	if err != nil {
		return nil,,"", err
	}
	// 订单
	//var orderInfo amodel.OrderInfo
	orderInfoVo.ItemType = in.ItemType
	orderInfoVo.OriginalAmount = int64(originalPrice)
	orderInfoVo.DerateAmount = int64(deratePrice)
	orderInfoVo.OrderAmount = int64(finalPrice)
	// 防止
	orderInfoVo.TradeNo = tradeNo
	orderInfoVo.OrderDetailVoList = orderDetailVoList
	orderInfoVo.OrderDerateVoList = orderDerateVoList
	now := time.Now().UnixMilli()
	orderInfoVo.Timestamp = now
	orderInfoVo.PayWay = ""
	data, err := json.Marshal(&orderInfoVo)
	if err != nil {
		return nil,"", err
	}
	hash := md5.New()
	hash.Write(data)
	signature := hex.EncodeToString(hash.Sum(nil))
	// 把签名单独返回出去,不然没法校验
	orderInfoVo.Sign = signature
	return &orderInfoVo,signature, nil
}
